#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
#include <functional>
#include <jsoncpp/json/value.h>
#include <mutex>
#include <unordered_map>
#include <vector>


namespace rpc
{
    namespace server
    {
        enum class VType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT
        };
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallBack = std::function<void(const Json::Value&, Json::Value&)>;
            using ParamsDescribe = std::pair<std::string, VType>;
            ServiceDescribe(const std::string &&mname, ServiceCallBack &&handler, std::vector<ParamsDescribe> &&desc, VType vtype)
            :_method_name(std::move(mname)), _callback(std::move(handler)), _params_desc(std::move(desc)), _return_type(vtype)
            {}
            const std::string& method()
            {
                return _method_name;
            }
            bool ParamsCheck(const Json::Value &params)
            {
                //对params进行参数校验--判断参数字段是否存在，类型是否一致
                for(auto& desc : _params_desc)
                {
                    if(!params.isMember(desc.first))
                    {
                        ELOG("参数字段完整性校验失败！%s 字段缺失", desc.first.c_str());
                        return false;
                    }
                    if(!check(desc.second, params[desc.first]))
                    {
                        ELOG("%s 参数类型校验失败！", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }
            bool call(const Json::Value &params, Json::Value &result)
            {
                _callback(params, result);
                if(!returnTypeCheck(result))
                {
                    ELOG("回调处理函数的相应信息校验失败！");
                    return false;
                }
                return true;
            }
        private:
            bool returnTypeCheck(const Json::Value &val)
            {
                return check(_return_type, val);
            }
            bool check(VType vtype, const Json::Value &val)
            {
                switch (vtype) 
                {
                    case VType::BOOL : return val.isBool();
                    case VType::INTEGRAL : return val.isIntegral();
                    case VType::NUMERIC : return val.isNumeric();
                    case VType::STRING : return val.isString();
                    case VType::ARRAY : return val.isArray();
                    case VType::OBJECT : return val.isObject();
                    default: return false;
                }
            }
        private:
            std::string _method_name;
            ServiceCallBack _callback; //实际的业务处理回调
            std::vector<ParamsDescribe> _params_desc; //参数字段格式描述
            VType _return_type;
        };
        class SDescribeFactory
        {
        public:
           // static ServiceDescribe::ptr create();
           void setMethodName(const std::string &name)
           {
                _method_name = name;
           }
           void setReturnType(VType vtype)
           {
                _return_type = vtype;
           } 
           void setParamsDesc(const std::string &pname, VType vtype)
           {
                _params_desc.push_back({pname, vtype});
           }
           void setServiceCallBack(const ServiceDescribe::ServiceCallBack &cb)
           {
                _callback = cb;
           }
           ServiceDescribe::ptr build()
           {
                return std::make_shared<ServiceDescribe>(std::move(_method_name), std::move(_callback), std::move(_params_desc), _return_type);
           }
        private:
            std::string _method_name;
            ServiceDescribe::ServiceCallBack _callback; //实际的业务处理回调
            std::vector<ServiceDescribe::ParamsDescribe> _params_desc; //参数字段格式描述
            VType _return_type;
        };

        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;
            void insert(const ServiceDescribe::ptr &desc)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.insert({desc->method(), desc});
            }
            ServiceDescribe::ptr select(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _services.find(method_name);
                if(it == _services.end())
                {
                    return ServiceDescribe::ptr();
                }
                return it->second;
            }
            void remove(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.erase(method_name);
            }
        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> _services;
        };

        class RpcRouter
        {   
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            //这是注册到Dispatch模块针对rpc请求进行回调处理的业务函数
            void onRpcRequest(const rpc::BaseConnection::ptr &conn, rpc::RpcRequest::ptr &request)
            {
                //1.查询客户端请求的方法描述--判断当前服务端能否提供服务
                auto service = _service_managaer.select(request->method());
                if(service.get() == nullptr)
                {
                    ELOG("%s 服务未找到！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }
                //2.进行参数校验，确定能否提供服务
                if(service->ParamsCheck(request->params()) == false)
                {
                    ELOG("%s 服务参数校验失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                //3.调用业务回调接口进行业务处理
                Json::Value result;
                bool ret = service->call(request->params(), result);
                if(ret == false)
                {
                    ELOG("%s 服务参数校验失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }
                //4.处理完毕得到结果，组织响应，向客户端发送
                return response(conn, request, result, RCode::RCODE_OK);
            }
            void registerMethod(const ServiceDescribe::ptr &service)
            {
                return _service_managaer.insert(service);
            }
        private:
            void response(const BaseConnection::ptr &conn, const RpcRequest::ptr &req, const Json::Value &res, RCode rcode)
            {
                auto msg = MessageFactory::create<RPCResponse>();
                msg->setId(req->rid());
                msg->setResult(res);
                msg->setMtype(MType::RSP_RPC);
                msg->setRCode(rcode);
                conn->send(msg);
            }
        private:
            ServiceManager _service_managaer;
        };
    }
   
}